package com.androwit.engine;

import java.util.Map;

import com.androwit.engine.mapping.MappingField;
import com.androwit.engine.mapping.MappingFieldsDefiner;

/**
 * Chain of responsibility that handles {@link MappingFieldsDefiner}
 * 
 * e.g: You can use this class to handle mutliple content type csv files by
 * creating a separate {@link MappingFieldsDefiner} for each type and
 * implementing {@link #handles(String[])} to take the responsibility of
 * handling the object or delegating it to the chain.
 * 
 * @author Zied Hamdi Founder of http://1vu.fr,  Zied Hamdi
 * 
 */
public abstract class FieldsDefinerHandler<J, K, V> implements
		MappingFieldsDefiner<J, K, V> {

	protected MappingFieldsDefiner<J, K, V> next;

	public FieldsDefinerHandler() {
		this(null);
	}

	public FieldsDefinerHandler(MappingFieldsDefiner<J, K, V> next) {
		this.next = next;
	}

	public MappingFieldsDefiner<J, K, V> getNext() {
		return next;
	}

	public void setNext(MappingFieldsDefiner<J, K, V> next) {
		this.next = next;
	}

	public final Object createInstance(Map<K, V> values) {
		if (handles(values))
			return createConcreteInstance(values);

		return next == null ? null : next.createInstance(values);
	}

	@Override
	public final MappingField<J, K, V>[] getMappedFields(Map<K, V> values) {
		if (handles(values))
			return getConcreteMappingFields(values);
		return next == null ? null : next.getMappedFields(values);
	}

	@Override
	public final MappingField<J, K, V>[] getMappingFields(Object value) {
		if (handles(value))
			return getConcreteMappedFields(value);
		return next == null ? null : next.getMappingFields(value);
	}

	protected abstract MappingField<J, K, V>[] getConcreteMappingFields(
			Map<K, V> values);

	protected abstract MappingField<J, K, V>[] getConcreteMappedFields(
			Object value);

	protected abstract Object createConcreteInstance(Map<K, V> values);

	protected abstract boolean handles(Map<K, V> values);

	protected abstract boolean handles(Object value);

}
